package com.fastloan.mgt.product.approve.service.impl;


import com.fastloan.common.BasicServiceImpl;
import com.fastloan.mgt.product.approve.dao.ProductApproveMapper;
import com.fastloan.mgt.product.approve.model.ProductApprove;
import com.fastloan.mgt.product.approve.model.vo.ProductApproveVo;
import com.fastloan.mgt.product.approve.service.ProductApproveService;
import com.fastloan.safe.core.util.ManagerKit;
import com.kawins.result.ResultEnum;
import com.kawins.result.ResultTo;
import com.kawins.supers.table.manager.DataTable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static com.fastloan.mgt.product.enums.ProductEnum.PUBLISHED;
import static com.fastloan.mgt.product.enums.ProductEnum.UNPUBLISHED;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

/**
 * @author chenkai
 * createTime 2017-10-2017/10/20 16:09
 */
@Service
public class ProductApproveServiceImpl extends BasicServiceImpl<ProductApprove> implements ProductApproveService {
    @Autowired
    private ProductApproveMapper approveMapper;

    @Override
    public ResultTo getNodeNameList(String productId) {
        ProductApprove productApprove = new ProductApprove();
        productApprove.setProductId(productId);
        List<ProductApprove> temporaryList = select(productApprove)
                .parallelStream()
                .collect(toList());
        return new ResultTo().setData(temporaryList);
    }

    @Override
    public ResultTo update(ProductApprove productApprove) {
        try {
            decisionNode(productApprove);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultTo(ResultEnum.OPERATION_FAILED, e.getMessage());
        }
        return updateByPrimaryKeySelective(productApprove) != 0 ? new ResultTo() : new ResultTo(ResultEnum.OPERATION_FAILED);
    }

    @Override
    public Integer add(ProductApprove productApprove) {
        try {
            decisionNode(productApprove);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int selective = insertSelective(productApprove);
        log.debug("插入流程节点, 节点id:{}, 产品id:{}, 操作人id:{}, 操作时间{}", productApprove.getApproveId(), productApprove.getProductId()
                , ManagerKit.getUserId(), LocalDateTime.now());
        return selective;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultTo changeApprove(String approveIds) {
        List<ProductApprove> productApproveList = Arrays.stream(approveIds.split(","))
                .map(this::selectByPrimaryKey)
                .collect(toList());
        ProductApprove productApprove = productApproveList.stream().findFirst().get();
        approveMapper.resetOrder(productApprove.getProductId());
        order(productApproveList);
        return new ResultTo();
    }


    /**
     * 设置审核顺序
     *
     * @param productApproveList
     */
    private void order(List<ProductApprove> productApproveList) {
        int order = 0;
        ProductApprove approve = productApproveList.parallelStream().findFirst().get();
        if (!approve.getStartNode().equals(PUBLISHED.getType())) {
            log.error("第一个节点必须是开始节点");
            throw new RuntimeException("第一个节点必须是开始节点");
        }
        for (int i = 0; i < productApproveList.size(); i++) {
            ProductApprove productApprove = productApproveList.get(i);
            ProductApprove nextProductApprove;
            if (productApproveList.size() != i + 1) {
                nextProductApprove = productApproveList.get(i + 1);
            } else {
                nextProductApprove = productApproveList.get(i);
                if (!nextProductApprove.getFinalNode().equals(PUBLISHED.getType())) {
                    log.error("最后一个节点必须是结束节点");
                    throw new RuntimeException("最后一个节点必须是结束节点");
                }
            }
            productApprove.setNextNodeId(nextProductApprove.getApproveId());
            productApprove.setOrderBy(order);
            updateByPrimaryKeySelective(productApprove);
            order++;
        }
    }

    @Override
    public ResultTo approveOrder(String productId) {
        ProductApprove approve = new ProductApprove();
        approve.setProductId(productId);
        List<ProductApprove> productApproveList = select(approve);
        List<ProductApprove> list = productApproveList.parallelStream()
                .filter(productApprove -> productApprove.getOrderBy() != null)
                .sorted(Comparator.comparing(ProductApprove::getOrderBy))
                .collect(toList());
        List<ProductApprove> collect = productApproveList.parallelStream()
                .filter(productApprove -> productApprove.getOrderBy() == null)
                .collect(toList());
        return new ResultTo().setData("order", list).setData("unsorted", collect);
    }

    @Override
    public Integer insertList(List<ProductApprove> list) {
        return approveMapper.insertList(list);
    }

    @Override
    public ResultTo getNodeInfo(String approveId) {
        ProductApprove approve = selectByPrimaryKey(approveId);
        ProductApproveVo productApproveVo = new ProductApproveVo();
        productApproveVo.setProductApprove(approve);
        return new ResultTo().setData(productApproveVo);
    }

    @Override
    @DataTable(name = "nodePageList")
    public List<ProductApprove> nodePageList(Map<String, Object> map) {
        Example example = new Example(ProductApprove.class);
        example.createCriteria().andEqualTo("productId", map.get("productId"));
        return selectByExample(example);
    }

    @Override
    public Integer approveCount(String productId) {
        Example example = new Example(ProductApprove.class);
        example.createCriteria().andEqualTo("productId", productId)
                .andEqualTo("status", UNPUBLISHED.getType());
        return selectCountByExample(example);
    }

    /**
     * 新增/更新节点验证
     *
     * @param productApprove
     */
    private void decisionNode(ProductApprove productApprove) {
        ProductApprove approve = new ProductApprove();
        approve.setProductId(productApprove.getProductId());
        List<ProductApprove> productApproveList = select(approve);
        ProductApprove beForeApprove;
        boolean flag = true;
        boolean mark = true;
        if (productApprove.getApproveId() != null) {
            beForeApprove = selectByPrimaryKey(productApprove.getApproveId());
            flag = beForeApprove.getStartNode().equals(UNPUBLISHED.getType());
            mark = beForeApprove.getFinalNode().equals(UNPUBLISHED.getType());
        }
        //新增/更新起始节点
        if (flag && productApprove.getStartNode().equals(PUBLISHED.getType())) {
            if (stream(productApproveList, approves -> approves.getStartNode().equals(PUBLISHED.getType())) > 0) {
                log.error("已存在开始节点");
                throw new RuntimeException("已存在开始节点");
            }
        }
        //新增/更新结束节点
        if (mark && productApprove.getFinalNode().equals(PUBLISHED.getType())) {
            if (stream(productApproveList, approves -> approves.getFinalNode().equals(PUBLISHED.getType())) > 0) {
                log.error("已存在结束节点");
                throw new RuntimeException("已存在结束节点");
            }
        }
    }

    private <T> long stream(List<T> list, Predicate<T> predicate) {
        return list.parallelStream()
                .filter(predicate)
                .count();
    }

}
